package device;

import communication.Communicator;
import communication.definitions.DeviceType;
import communication.definitions.ReceivedFunction;
import communication.exceptions.InvalidArgumentsException;
import communication.exceptions.InvalidFunctionException;

/**
 * Devices are the backbone of the Windex Framework. Everything from a single
 * ADC channel, to the entire robot itself may be considered a device.
 * <p>
 * Each device on the client can be uniquely identified by two attributes: its
 * <i>type</i>, and its <i>ID</i>.
 * <p>
 * A <i>type</i> is the simplest discrete robot-side implementation from which a
 * device is derived. For example, the type of both a potentiometer and an
 * infrared range finder would be an ADC if neither the potentiometer nor
 * infrared functions are implemented on the robot. They may implement different
 * interfaces, but they should both extend ADC on the client.
 * <p>
 * The second identifying feature of a device is its <i>ID</i>. A device ID must
 * be unique among other devices of the same type, but two devices of different
 * types may share an ID. The ID is almost always something meaningful; it may,
 * for example, represent the ADC channel of an ADC object.
 * 
 * @author Peter Kalauskas
 */
public abstract class Device {
	private DeviceType type;
	private byte id; // the ID of this device
	protected Communicator comm;

	/**
	 * Constructs a new device with the given type and id.
	 * 
	 * @param type
	 *            the type of this device
	 * @param id
	 *            the id of this device. When possible this should be something
	 *            meaningful, such as an ADC channel since it will always be
	 *            sent to the robot as an argument.
	 * @param comm
	 *            the communicator which this device will use
	 */
	public Device(DeviceType type, byte id, Communicator comm) {
		this.type = type;
		this.id = id;
		this.comm = comm;
	}

	/**
	 * Returns the type of this device.
	 * 
	 * @return the DeviceType of this device
	 */
	public DeviceType getType() {
		return type;
	}

	/**
	 * Returns the ID of this device
	 * 
	 * @return the ID of this device
	 */
	public byte getID() {
		return id;
	}

	/**
	 * Handles, and calls, the appropriate function using the given arguments.
	 * This function should only be called by the dispatcher, which will check
	 * to make sure the appropriate number of arguments are passed in. As a
	 * fail-safe, this function will also check to make sure the passed function
	 * is implemented and check if the number of arguments are correct.
	 * 
	 * @param f
	 *            the function to be called, if this function does not exist for
	 *            this device nothing will happen.
	 * @param args
	 *            the arguments to pass into the function. It is assumed that
	 *            the number of arguments agrees with f.arguments().
	 * @throws InvalidArgumentsException
	 * @throws InvalidFunctionException
	 */
	public void receiveFunction(ReceivedFunction f, byte[] args)
			throws InvalidArgumentsException, InvalidFunctionException {
		f.checkArguments(args);
	}
}
